﻿//This file is part of Search Engine by Tomasz Kusienicki.
// 
//This Search Engine is free software: you can redistribute it and/or modify
//it under the terms of the GNU General Public License as published by
//the Free Software Foundation, either version 3 of the License, or
//any later version.
// 
//Foobar is distributed in the hope that it will be useful,
//but WITHOUT ANY WARRANTY; without even the implied warranty of
//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
//GNU General Public License for more details.
// 
//You should have received a copy of the GNU General Public License
//on <http://www.gnu.org/licenses/>.

using System;
using System.Collections.Generic;
using System.Data.Linq;
using System.Data.SqlClient;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
using System.Windows.Forms;
using AdminApp1.Common;
using AdminApp1.Models;
using AdminApp1.Views;

namespace AdminApp1.Presenters
{
    public class MapPresenter : PresenterBase<MapView, MapPresenter, MapModel>
    {

        #region variables
        private SearchEngineDatabaseDataContext _dc;
        private List<Image> _maps;
        #endregion

        #region Constructor
        public MapPresenter(MapView view, MapModel model, SearchEngineDatabaseDataContext searchEngineDatabaseDataContext) 
            : base(view, model)
        {
            Model.Gate = false;
            Model.MaxWidth = 800;
            Model.MaxHeight = 500;
            _dc = searchEngineDatabaseDataContext;
            LoadData();
            AdjustTableSize();
        }
        #endregion


        #region LoadData, ImageToByteArray, ByteArrayToImage
        private void LoadData()
        {
            _maps = new List<Image>();

            try
            {
                var q = from a in _dc.GetTable<Map>() select a;
                View.dataGridView1.DataSource = q;
                View.dataGridView1.Columns[3].Visible = false;

                foreach (var map in q)
                {
                    _maps.Add(map.map != null ? ByteArrayToImage(map.map.ToArray()) : null);
                }

                var imageColumn = new DataGridViewImageColumn
                {
                    ImageLayout = DataGridViewImageCellLayout.Stretch,
                    Name = "Image",
                    HeaderText = @"Image",
                    Image = Properties.Resources.empty
                };
                View.dataGridView1.Columns.Add(imageColumn);
            }
            catch (SqlException)
            {
                MessageBox.Show(@"Database is not valid", @"SqlException", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        public byte[] ImageToByteArray(Image imageIn)
        {
            var ms = new MemoryStream();
            imageIn.Save(ms, ImageFormat.Png);
            return ms.ToArray();
        }

        public Image ByteArrayToImage(byte[] byteArrayIn)
        {
            try
            {
                var ms = new MemoryStream(byteArrayIn);
                var returnImage = Image.FromStream(ms);
                return returnImage;
            }
            catch (ArgumentException){}
            return null;
        }
        #endregion

        #region AdjustTableSize
        private void AdjustTableSize()
        {
            var preferredWidth = View.dataGridView1.PreferredSize.Width;
            var preferredHeight = View.dataGridView1.PreferredSize.Height;
            var newSize = new Size
            {
                Width = Model.MaxWidth > preferredWidth ? preferredWidth : Model.MaxWidth,
                Height = Model.MaxHeight > preferredHeight ? preferredHeight : Model.MaxHeight
            };
            View.Size = newSize;
        }
        #endregion

        #region HandleOnClosed, UpdateException
        public void HandleOnClosed()
        {
            Cursor.Current = Cursors.WaitCursor;
            var name = View.Text;
            var all = View.dataGridView1.Rows.Count-1;
            if (_maps.Count >= View.dataGridView1.Rows.Count)
            {
                _maps[View.dataGridView1.Rows.Count-1] = null;
            }
            for (var i = 0; i < View.dataGridView1.Rows.Count-1; i++)
            {
                View.Text = string.Format("{0} - {1}/{2}", name, i, all);
                Model.Gate = false;

                if (_maps[i] == null)
                {
                    UpdateException();
                    View.Text = name;
                    return;
                }

                try
                {
                    HandleInsertOrUpdate(
                        View.dataGridView1.Rows[i].Cells[1].Value.ToString(),
                        View.dataGridView1.Rows[i].Cells[2].Value.ToString(),
                        View.dataGridView1.Rows[i].Cells[3].Value == null ? " " : View.dataGridView1.Rows[i].Cells[3].Value.ToString(),
                        ImageToByteArray(_maps[i]),
                        View.dataGridView1.Rows[i].Cells[5].Value.ToString(),
                        View.dataGridView1.Rows[i].Cells[6].Value.ToString(),
                        View.dataGridView1.Rows[i].Cells[7].Value.ToString(),
                        View.dataGridView1.Rows[i].Cells[8].Value.ToString());
                }
                catch (NullReferenceException)
                {
                    UpdateException();
                    View.Text = name;
                    return;
                }
                catch (ArgumentOutOfRangeException){}
                catch (ArgumentNullException)
                {
                    HandleUpdateException();
                }
                catch (InvalidOperationException)
                {
                    UpdateException();
                    View.Text = name;
                    return;
                }
                catch (SqlException)
                {
                    UpdateException();
                    View.Text = name;
                    return;
                }
            }
            View.Text = name;
            View.Hide();
        }

        private void UpdateException()
        {
            if (MessageBox.Show(@"Database could not be updated. Check data store integrity and fill the non-nullable columns. " +
                @"Please contact the administrator if this problem persists.", @"SqlException",
                MessageBoxButtons.OKCancel, MessageBoxIcon.Error) == DialogResult.Cancel)
            {
                _dc = new SearchEngineDatabaseDataContext();
                LoadData();
                View.Hide();
            }
        }
        #endregion

        #region HandleUpdateException
        public void HandleUpdateException()
        {
            MessageBox.Show(@"Wrong data type or this is the non-nullable column! Delete invalid data to reset the cell.", @"SqlException", MessageBoxButtons.OK, MessageBoxIcon.Error);
        }
        #endregion

        #region HandleInsertOrUpdate
        public void HandleInsertOrUpdate(string mapId, string name, string details, byte[] map1, string locationTopN, string locationTopE, string locationBottomN, string locationBottomE)
        {
            var matched = (
                from c in _dc.GetTable<Map>()
                where c.mapId == int.Parse(mapId)
                select c
                ).SingleOrDefault();

            if (matched == null)
            {
                var maps = _dc.GetTable<Map>();
                var map = new Map
                {
                    mapId = short.Parse(mapId),
                    name = name,
                    details = details,
                    map = new Binary(map1),
                    locationTopN = double.Parse(locationTopN),
                    locationTopE = double.Parse(locationTopE),
                    locationBottomN = double.Parse(locationBottomN),
                    locationBottomE = double.Parse(locationBottomE)
                };
                maps.InsertOnSubmit(map);
                maps.Context.SubmitChanges();
            }
            else
            {
                matched.mapId = short.Parse(mapId);
                matched.name = name;
                matched.details = details;
                matched.map = new Binary(map1);
                matched.locationTopN = double.Parse(locationTopN);
                matched.locationTopE = double.Parse(locationTopE);
                matched.locationBottomN = double.Parse(locationBottomN);
                matched.locationBottomE = double.Parse(locationBottomE);
                _dc.SubmitChanges();
            }
        }
        #endregion

        #region HandleDelete
        public void HandleDelete(string mapId)
        {
            var matched = (
                from c in _dc.GetTable<Map>()
                where c.mapId == int.Parse(mapId)
                select c
                ).SingleOrDefault();

            if (matched != null)
            {
                _dc.Maps.DeleteOnSubmit(matched);
                _dc.SubmitChanges();
            }
        }
        #endregion

        #region HandleKeyDown
        public void HandleKeyDown(object sender, KeyEventArgs e)
        {
            switch (e.KeyCode)
            {
                case Keys.Delete:
                    foreach (DataGridViewRow item in View.dataGridView1.SelectedRows)
                    {
                        try
                        {
                            HandleDelete(item.Cells[1].Value.ToString());
                            _maps[item.Index] = null;
                            View.dataGridView1.Rows.RemoveAt(item.Index);
                        }
                        catch (SqlException)
                        {
                            MessageBox.Show(@"Selected row could not be delete. Check data store integrity. " +
                                            @"Please contact the administrator if this problem persists.",
                                            @"SqlException",
                                            MessageBoxButtons.OK, MessageBoxIcon.Error);

                            _dc = new SearchEngineDatabaseDataContext();
                            LoadData();
                            return;
                        }
                    }
                    break;
            }
        }
        #endregion

        #region HandleCellFormatting, HandleMapFormatting
        public void HandleCellFormatting(object sender, DataGridViewCellFormattingEventArgs e)
        {
            if (View.dataGridView1.Columns[e.ColumnIndex].Name == "Image")
            {
                try
                {
                    if (_maps.Count > e.RowIndex && _maps[e.RowIndex] != null)
                    {
                        //e.Value = _maps[e.RowIndex];
                        e.Value = Properties.Resources.map1;
                    }
                    else
                    {
                        e.Value = Properties.Resources.empty;
                    }
                }
                catch(ArgumentOutOfRangeException){}
            }
        }

        public void HandleMapFormatting(int rowIndex)
        {
            if (!Model.Gate) return;
            var dialog = new OpenFileDialog
                             {
                                 Filter = @"png (*.png)|*.png|jpg (*.jpg)|*.jpg|bmp (*.bmp)|*.bmp|All files (*.*)|*.*",
                                 Title = @"Select a map file"
                             };
            var path = (dialog.ShowDialog() == DialogResult.OK) ? dialog.FileName : null;
            if (path != null)
            {
                if (_maps.Count <= rowIndex)
                {
                    _maps.Add(Image.FromFile(path));
                }
                else
                {
                    _maps[rowIndex] = Image.FromFile(path);
                }
            }
        }
        #endregion

    }
}
